﻿using System;
using System.Runtime.Serialization;

namespace EzDesk.Utility.ServiceStatusInfo
{
    [DataContract]
    public class StatusInfo<TResult> : StatusInfo
    {
        public StatusInfo(Exception ex, string info = null)
            : base(ex, info)
        {
        }

        public StatusInfo(ServiceStatus serviceStatus = ServiceStatus.Success, string info = null)
            : base(serviceStatus, info)
        {
        }

        public StatusInfo(TResult result, ServiceStatus serviceStatus = ServiceStatus.Success, string info = null)
            : base(serviceStatus, info)
        {
            Result = result;
        }

        private TResult _result;

        [DataMember]
        public TResult Result
        {
            get
            {
                if (!HasResult)
                {
                    throw new InvalidOperationException("No result has been provided.");
                }
                return _result;
            }
            set
            {
                _result = value;
                HasResult = true;
            }
        }

        [DataMember]
        public bool HasResult { get; private set; }

        public StatusInfo ToSimpleStatusInfo()
        {
            var simpleStatusInfo = new StatusInfo(Status, Info)
                                       {
                                           Data = Data
                                       };
            return simpleStatusInfo;
        }
    }

    [DataContract]
    public class StatusInfo
    {
        [DataMember]
        public ServiceStatus Status { get; set; }

        [DataMember]
        public string Info { get; set; }

        /// <summary>
        /// 这个字段只适合在Controller给View传递附加数据使用，Service里面别用
        /// </summary>
        [DataMember]
        public dynamic Data { get; set; }


        public StatusInfo(Exception ex, string info = null)
            : this(ServiceStatus.Error, info ?? ex.Message)
        {
        }

        public StatusInfo(ServiceStatus serviceStatus = ServiceStatus.Success, string info = null)
        {
            Status = serviceStatus;
            Info = info;
        }


        public StatusInfo(string info)
            : this(ServiceStatus.Success, info)
        {

        }

        public static StatusInfo<TResult> Wrap<TResult>(Func<TResult> proc)
        {
            try
            {
                return new StatusInfo<TResult>(proc());
            }
            catch(Exception ex)
            {
                return new StatusInfo<TResult>(ex);
            }
        }


        public static StatusInfo Wrap(Action proc)
        {
            try
            {
                proc();
                return new StatusInfo();
            }
            catch(Exception ex)
            {
                return new StatusInfo(ex);
            }
        }

    }
}